﻿using System;
using System.Collections;

using BizElements.Core;

namespace BizElements.BusinessLayer
{
    /// <summary>
    /// Collection of <see cref="SearchField"/> objects.
    /// </summary>
    [Serializable]
    public sealed class SearchFieldCollection : ISearchEngineFieldCollection
    {
        #region Fields.

        ArrayList list = new ArrayList();
        string name;
        string description;

        #endregion

        #region Add, Remove, Clear.

        /// <summary>
        /// Adds a field to the collection.
        /// </summary>
        /// <param name="field">Field.</param>
        /// <returns>Field that was added to the collection.</returns>
        public SearchField Add(SearchField field)
        {
            this.list.Add(field);
            return field;
        }

        /// <summary>
        /// Adds a field to the collection.
        /// </summary>
        /// <param name="field">Database column.</param>
        /// <param name="caption">Field caption.</param>
        /// <returns>Field that was added to the collection.</returns>
        public SearchField Add(IDbColumn field, string caption)
        {
            return Add(new SearchField(field, caption));
        }

        /// <summary>
        /// Adds a new hidden field to the collection.
        /// </summary>
        /// <param name="field">Database column.</param>
        /// <returns>Field that was added to the collection.</returns>
        public SearchField AddHiddenField(IDbColumn field)
        {
            return AddHiddenField(field, "");
        }

        /// <summary>
        /// Adds a new hidden field to the collection.
        /// </summary>
        /// <param name="field">Database column.</param>
        /// <param name="caption">Field caption.</param>
        /// <returns>Field that was added to the collection.</returns>
        public SearchField AddHiddenField(IDbColumn field, string caption)
        {
            SearchField newField = new SearchField(field, caption);
            newField.IsHidden = true;
            return Add(newField);
        }

        /// <summary>Removes the field with the specified name.</summary>
        /// <param name="bindingName">Alias/name of the item.</param>
        public void Remove(string bindingName)
        {
            int idxOfItemToRemove = ArrayUtil.IndexOf<IBindableField>(this.list, (field) => (field.BindingName == bindingName));
            if (idxOfItemToRemove >= 0)
                this.list.RemoveAt(idxOfItemToRemove);
        }

        /// <summary>Remove all elements from the collection.</summary>
        public void Clear()
        {
            this.list.Clear();
        }

        #endregion

        #region Properties and indexers.

        /// <summary>
        /// Gets the element at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the element to get or set. </param>
        /// <returns>The element at the specified index.</returns>
        public SearchField this[int index]
        {
            get { return (SearchField)this.list[index]; }
        }

        ISearchEngineField ISearchEngineFieldCollection.this[int index]
        {
            get { return this[index]; }
        }

        /// <summary>
        /// Searches the collection for the field with the specified <see cref="SearchField.BindingName"/>.
        /// </summary>
        /// <param name="bindingName">Alias/name of the field.</param>
        /// <returns>Specified field or <b>null</b> if a field with the given name is not found in the collection.</returns>
        public SearchField this[string bindingName]
        {
            get
            {
                foreach (SearchField field in this.list)
                {
                    if (field.BindingName == bindingName)
                        return field;
                }

                return null;
            }
        }

        ISearchEngineField ISearchEngineFieldCollection.this[string alias]
        {
            get { return this[alias]; }
        }

        /// <summary>
        /// Searches the collection for the field that accesses specified database column.
        /// </summary>
        /// <param name="field">Database column.</param>
        /// <returns>Specified field or <b>null</b> it is not found in the collection.</returns>
        public SearchField this[IDbColumn field]
        {
            get
            {
                foreach (SearchField searchField in this.list)
                {
                    if (searchField.Field.Alias == field.Alias)
                        return searchField;
                }

                return null;
            }
        }

        /// <summary>
        /// Gets the number of elements actually contained in the collection.
        /// </summary>
        public int Count
        {
            get { return this.list.Count; }
        }

        /// <summary>
        /// Gets or sets optional filter name.
        /// </summary>
        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

        /// <summary>
        /// Gets or sets optional filter description.
        /// </summary>
        public string Description
        {
            get { return this.description; }
            set { this.description = value; }
        }

        #endregion

        #region IEnumerable.

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.list.GetEnumerator();
        }

        #endregion

        #region ResetAllFields.

        /// <summary>
        /// Resets all fields to their default state.
        /// </summary>
        public void ResetAllFields()
        {
            foreach (ISearchEngineField field in this)
            {
                field.AddWithOr = false;
                field.BeginValue = null;
                field.EndValue = null;
                field.Negate = false;
                field.Values = null;
                field.SelectedValueSetKey = null;
                field.IsNull = false;
            }
        }

        /// <summary>
        /// Resets all fields that match the specified criteria to their default state.
        /// </summary>
        /// <param name="resetAutoPopulatedFields">Indicates whether the fields whose <see cref="ISearchEngineField.IsAutoPopulated"/> property is set to <b>true</b> are to be reset.</param>
        /// <param name="resetHiddenFields">Indicates whether the fields whose <see cref="IBindableField.IsHidden"/> property is set to <b>true</b> are to be reset.</param>
        public void ResetAllFields(bool resetAutoPopulatedFields, bool resetHiddenFields)
        {
            foreach (ISearchEngineField field in this)
            {
                if (field.IsAutoPopulated && !resetAutoPopulatedFields)
                    continue;

                if (field.IsHidden && !resetHiddenFields)
                    continue;

                field.AddWithOr = false;
                field.BeginValue = null;
                field.EndValue = null;
                field.Negate = false;
                field.Values = null;
                field.SelectedValueSetKey = null;
                field.IsNull = false;
            }
        }

        #endregion
    }
}
